package com.demo.aop;

import com.demo.aop.advice.Advice;
import com.demo.aop.advice.AfterReturningAdvice;
import com.demo.aop.advice.MethodBeforeAdvice;
import com.demo.aop.advice.MethodIntercepterAdvice;

import java.lang.reflect.Method;
import java.util.List;

public class InvocationHandleMethodChain {

    private List<Advice> adviceList;

    private Object target;

    private Method targetMethod;

    private Object[] args;

    private int count = 0;

    private static Method invoke;

    public InvocationHandleMethodChain(List<Advice> adviceList,Object target,Method targetMethod,Object[] args){
        this.adviceList = adviceList;
        this.target = target;
        this.targetMethod = targetMethod;
        this.args = args;
    }

    static {
        try {
            invoke = InvocationHandleMethodChain.class.getMethod("invoke");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public Object invoke() throws Exception {
        if (adviceList !=null && count < adviceList.size()) {
            Advice advice = adviceList.get(count++);
            if (advice instanceof MethodBeforeAdvice) {
                ((MethodBeforeAdvice) advice).methodBefore(targetMethod, target, args);
            } else if (advice instanceof MethodIntercepterAdvice) {
                return ((MethodIntercepterAdvice) advice).intercep(invoke, this, null);
            } else if (advice instanceof AfterReturningAdvice) {
                Object invoke = this.invoke();
                ((AfterReturningAdvice) advice).afterReturing(targetMethod, target, args,invoke );
                return invoke;
            }
            return this.invoke();
        }else{
            return targetMethod.invoke(target, args);
        }
    }

}
